/**
 * @file mod_com.cpp
 * @author your name (you@domain.com)
 * @brief
 * @version 0.1
 * @date 2025-06-20
 *
 * @copyright Copyright (c) 2025
 *
 */

#include "mod_com.h"
#include <fstream>
#include <iostream>
#include <string>    // 对于转换为字符串的操作，需要包含这个头文件
#include <vector>
#include <windows.h>

#define MIN_(a, b) (((a) < (b)) ? (a) : (b))

#include "mod_ringbuffer.h"
CRITICAL_SECTION ringbuffer_cs;

// 全局变量
HANDLE           h_Com;                    // 串口句柄
HANDLE           hReceiveThread = NULL;    // 接收线程句柄
static bool      keep_receiving = false;
CRITICAL_SECTION com_cs;    // 用于线程同步的临界区

// 线程
DWORD WINAPI serialReceiveThread(LPVOID lpParam) {
    uint8_t buffer[256];

    while (keep_receiving) {
        DWORD   dwError = 0;
        COMSTAT comStat = {0};

        // 获取通信状态并清空错误标志
        if (!ClearCommError(h_Com, &dwError, &comStat)) {
            std::cerr << "ClearCommError 失败 (错误码: 0x" << std::hex << GetLastError() << ")" << std::endl;
            continue;
        }

        // 计算实际需要读取的字节数
        const DWORD bytes_available = comStat.cbInQue;
        if (bytes_available == 0) {
            Sleep(2);    // 稍微休眠避免CPU占用过高
            continue;
        }

        DWORD dwRead        = 0;
        DWORD bytes_to_read = MIN_(bytes_available, sizeof(buffer));
        if (!ReadFile(h_Com, buffer, bytes_to_read, &dwRead, NULL)) {
            std::cerr << "数据读取失败 (错误码: 0x" << std::hex << GetLastError() << ")" << std::endl;
            continue;
        }

        // 调试输出：打印收到的字节数和内容
        // printf("serialReceiveThread: 收到 %lu 字节\n", dwRead);
        // printf("原始数据: ");
        // for (DWORD i = 0; i < dwRead; i++) {
        //     printf("%02X ", buffer[i]);
        // }
        // printf("\n");

        if (dwRead > 0) {
            EnterCriticalSection(&ringbuffer_cs);    // 进入临界区
            // 写入环形缓冲区
            if (writeRingbuffer(buffer, dwRead) != 0) {
                std::cerr << "写入环形缓冲区失败" << std::endl;
            }
            LeaveCriticalSection(&ringbuffer_cs);    // 离开临界区
        }
    }

    return 0;
}

/**
 * @brief 打开串口
 *
 * @param fullportName
 */
bool ConnectCom(const char *fullportName) {
    COMMTIMEOUTS TimeOuts;    // 串口设置超时结构体
    DCB          dcb;
    SetConsoleOutputCP(CP_UTF8);

    // 初始化临界区
    InitializeCriticalSection(&com_cs);
    InitializeCriticalSection(&ringbuffer_cs);    // 初始化

    // 打开一个串口设备
    h_Com = CreateFileA(fullportName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, DWORD(NULL), NULL);

    if (h_Com == INVALID_HANDLE_VALUE) {
        std::cout << "串口打开失败" << std::endl;
        DeleteCriticalSection(&com_cs);
        return false;
    }

    SetupComm(h_Com, 4096, 4096);    // 设置输入输出缓冲
    // 超时设置
    TimeOuts.ReadIntervalTimeout        = 100;
    TimeOuts.ReadTotalTimeoutMultiplier = 500;
    TimeOuts.ReadTotalTimeoutConstant   = 0;

    TimeOuts.WriteTotalTimeoutMultiplier = 0;
    TimeOuts.WriteTotalTimeoutConstant   = 0;

    SetCommTimeouts(h_Com, &TimeOuts);
    // 设置串口属性
    GetCommState(h_Com, &dcb);    // 串口属性配置
    dcb.BaudRate = 115200;
    dcb.ByteSize = 8;
    dcb.StopBits = ONESTOPBIT;
    dcb.Parity   = NOPARITY;

    if (!SetCommState(h_Com, &dcb)) {
        CloseHandle(h_Com);
        DeleteCriticalSection(&com_cs);
        std::cout << "串口配置失败" << std::endl;
        return false;
    }
    PurgeComm(h_Com, PURGE_TXCLEAR | PURGE_RXCLEAR | PURGE_TXABORT | PURGE_RXABORT);    // 清空串口缓冲区

    // 初始化环形缓冲区
    initRingbuffer();

    // 启动串口接收线程
    keep_receiving = true;
    DWORD threadId;
    hReceiveThread = CreateThread(NULL,                   // 默认安全属性
                                  0,                      // 默认堆栈大小
                                  serialReceiveThread,    // 线程函数
                                  NULL,                   // 线程参数
                                  0,                      // 默认创建标志
                                  &threadId               // 接收线程标识符
    );

    if (hReceiveThread == NULL) {
        std::cout << "创建接收线程失败" << std::endl;
        CloseHandle(h_Com);
        DeleteCriticalSection(&com_cs);
        return false;
    }

    return true;
}

/**
 * @brief 关闭串口
 *
 */
void DisconnectCom() {
    // 停止接收线程
    keep_receiving = false;
    if (hReceiveThread != NULL) {
        WaitForSingleObject(hReceiveThread, 1000);    // 等待线程结束，最多1秒
        CloseHandle(hReceiveThread);
        hReceiveThread = NULL;
    }

    // 关闭串口句柄
    if (h_Com != INVALID_HANDLE_VALUE) {
        CloseHandle(h_Com);
        h_Com = INVALID_HANDLE_VALUE;
    }

    // 删除临界区
    DeleteCriticalSection(&com_cs);
    DeleteCriticalSection(&ringbuffer_cs);    // 删除

    // 释放环形缓冲区
    releaseRingbuffer();
}

/**
 * @brief 清空串口缓存
 *
 */
void CleanCom(void) {
    EnterCriticalSection(&com_cs);
    PurgeComm(h_Com, PURGE_TXCLEAR | PURGE_RXCLEAR | PURGE_TXABORT | PURGE_RXABORT);    // 清空串口缓冲区
    LeaveCriticalSection(&com_cs);
}

/**
 * @brief 串口数据写入
 *
 * @param data
 * @param len
 * @return int
 */
int CommDataWrite(char *data, int len) {
    EnterCriticalSection(&com_cs);
    // 发送
    DWORD dwError;
    DWORD dwSend = 0;
    PurgeComm(h_Com, PURGE_TXCLEAR | PURGE_RXCLEAR | PURGE_TXABORT | PURGE_RXABORT);    // 清空串口缓冲区
    if (ClearCommError(h_Com, &dwError, NULL)) {
        PurgeComm(h_Com, PURGE_TXABORT | PURGE_TXCLEAR);
    }

    if (!WriteFile(h_Com, (LPCVOID *)(data), len, &dwSend, NULL)) {
        std::cout << "发送失败" << std::endl;
        LeaveCriticalSection(&com_cs);
        return false;
    }

    LeaveCriticalSection(&com_cs);
    return true;
}

/**
 * @brief 从环形缓冲区读取数据
 *
 * @param data 数据缓冲区
 * @param len 请求读取的长度
 * @return int 实际读取的长度
 */
int CommDataRead(uint8_t *data, int len) {
    if (data == NULL || len <= 0) {
        std::cerr << "无效参数" << std::endl;
        return -1;
    }

    EnterCriticalSection(&ringbuffer_cs);
    uint32_t available = getRingbufferValidLen();
    if (available == 0) {
        LeaveCriticalSection(&ringbuffer_cs);
        printf("缓冲区为空\n");
        return 0;
    }

    // 确保不读取超过可用数据量
    int bytes_to_read = (len < available) ? len : available;
    int bytes_read    = readRingbuffer(data, bytes_to_read);
    LeaveCriticalSection(&ringbuffer_cs);

    // printf("从环形缓冲区读取 %d 字节: ", bytes_read);
    // for (int i = 0; i < bytes_read; i++) {
    //     printf("%02X ", data[i]);
    // }
    // printf("\n");

    return bytes_read;
}